class Funnel {
    constructor() {
        this.data = [];
        this.maxlength = 15;
    }

    toString() {
        let strView = '';
        let carret = 0;
        for (let i = 1; i <= 5; i++) {
            strView = ' '.repeat(5 - i) + '\\' + this.getDataToStr(carret, i) + '/' + (i > 1 ? '\n' : '') + strView;
            carret += i;
        }
        return strView;
    }

    fill(...items) {
        items.forEach(item => this.fillOne(item));
    }

    /*
     * Find the last empty dot and fill
     */
    fillOne(item) {
        let lastIndex = false;
        for (let index = this.maxlength - 1; index >= 0; index--) {
            if (this.data[index] === ' ' || typeof this.data[index] == 'undefined') {
                lastIndex = index;
            }
        }

        if (lastIndex !== false) this.data[lastIndex] = item;
    }

    drip() {
        if (this.data.length <= 0 || this.data[0] === ' ') return null;

        let downEl = this.data[0];
        this.data[0] = ' ';
        this.recalculateSpaces();

        return downEl;
    }

    /*
     * Calculate drops for each free space
     */
    recalculateSpaces() {
        this.data.forEach((item, i, arr) => {

            if (this.data[i] === ' ') {
                this.fillFreeSpaceDot(i);
            }
        });
    }

    /*
     * Fill free space by closest parent dot
     */
    fillFreeSpaceDot(index) {
        let dotRow = this.getDotRowNumber(index);
        let parent1 = index + dotRow + 1;
        let parent2 = parent1 + 1;
        let chosedParent = this.getMoreWeightPoint(parent1, parent2);

        if (chosedParent !== false) {
            let parentValue = this.data[chosedParent];
            this.data.splice(chosedParent, 1, ' ');
            this.data.splice(index, 1, parentValue);
        }
    }

    getMoreWeightPoint(index1, index2) {
        if (this.checkDot(index1) && this.checkDot(index2)) {
            return this.getDotParentsCount(index1) >= this.getDotParentsCount(index2) ? index1 : index2;
        } else {
            if (this.checkDot(index1)) {
                return index1;
            } else if (this.checkDot(index2)) {
                return index2;
            }
        }

        return false;
    }

    checkDot(index) {
        if (
            this.data[index] === ' '
            || typeof this.data[index] == 'undefined'
        ) return false;

        return true;
    }

    getDotParentsCount(index) {
        let dotRow = this.getDotRowNumber(index);
        let curIterDot = index + dotRow;
        let curMaxLength = 2;
        let curLength = 0;
        let dotCount = 0;

        while (curIterDot < this.data.length) {
            if (curLength >= curMaxLength) {
                curLength = 1;
                curMaxLength++;
                curIterDot += 1 + dotRow;
            } else {
                curLength++;
                curIterDot++;
            }

            if (curIterDot >= this.data.length) break;
            if (this.data[curIterDot] !== ' ' && typeof this.data[curIterDot] != 'undefined') {
                dotCount++;
            }
        }

        return dotCount;
    }

    getDotRowNumber(index) {
        let curMax = 0;
        let row = 0;
        while (index > curMax) {
            row++;
            curMax += row + 1;
            if (row > 10) break;
        }

        return row;
    }

    getDataToStr(start, count) {
        let havingElements = this.data.slice(start, start + count);
        let partToStr = havingElements.join(' ');

        if (partToStr.length < count * 2 - 1) {
            partToStr = partToStr + ' '.repeat(count * 2 - 1 - partToStr.length);
        }
        return partToStr;
    }
}
